from pytickee import errors, get_api
from pytickee.api import API
import logging

class ApiModel(object):
    retrieved = False
    data = {}
    
    def __init__(self, retrieve_params):
        self.retrieve_params = retrieve_params
        
    def retrieve(self):
        """
        Controls the fetching of addition information from the api.
        """
        api = get_api()
        if not isinstance(api, API):
            raise errors.TickeeError('Expected an API object.')
        if api:
            self.api = api
        else:
            self.api = API()
        self._retrieve()
        return self
        
    def populate(self, kwargs):
        """
        Sets the attributes of the object with the information from the database
        """
        if not isinstance(kwargs, dict):
            raise errors.TickeeError("No data found to populate object.")
        for key, value in kwargs.items():
            if key in self.mutations:
                value = self.mutations[key](value)
            self.data[key] = value
            
    def _query_api(self, api_method, params, payload=None):
        """
        Performs the query.
        """
        try:
            method = getattr(self.api, api_method)
            response = method(**params)
        except Exception as e:
            logging.error(e)
            logging.error('Failed to fetch data for %s with id=%s' % \
                          (self.__class__.__name__, self.id))
        else:
            if "error" in response:
                raise errors.TickeeError('Retrieval failed: %s' % \
                                         response['error'])
            logging.debug('API returned: %s' % response)
            if payload:
                return response[self.payload]
            else:
                return response
            
    def _retrieve(self):
        """
        Fetches the information of the object from the api.
        """
        result = self._query_api(self.retrieve_method, self.retrieve_params, self.payload)
        self.populate(result)
        self.retrieved = True
        
    def _require_retrieved(self):
        """
        Checks if data was already retrieved, if not errors.
        """
        if not self.retrieved:
            raise errors.TickeeError("Use .retrieve(api) first.")
    
    def __getattr__(self, name):
        if not self.retrieved:
            self.retrieve()
        if name in self.data.keys():
            return self.data[name]
        else:
            raise AttributeError


class Account(ApiModel):
    retrieve_method = 'account_show'
    payload = 'account'
    mutations = {'events': lambda event_list: map(Event, map(lambda e: e.get('id'), event_list))}
    def __init__(self, acc_id):
        retrieve_params = dict(account_id=acc_id, include_events=True)
        super(Account, self).__init__(retrieve_params)
        self.id = acc_id

class User(ApiModel):
    retrieve_method = 'users_show'
    payload = 'user'
    def __init__(self, usr_id):
        retrieve_params = dict(user_id=usr_id)
        super(User, self).__init__(retrieve_params)
        self.id = usr_id
        
    def __getattribute__(self, *args, **kwargs):
        event = self.event
        print "Calling getattr"
        print event
        return ApiModel.__getattribute__(self, *args, **kwargs)


class Event(ApiModel):
    retrieve_method = 'events_show'
    payload = 'event'
    
    def __init__(self, event_id):
        retrieve_params = dict(event_id=event_id)
        super(Event, self).__init__(retrieve_params)
        self.id = event_id